package com.xvyy.tingshu.search.locktest;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * ClassName: TestServiceImpl
 * Package: com.xvyy.tingshu.search.locktest
 *
 * @Description:
 * @Author: xvyy
 * @Create: 2025/2/6 - 12:50
 * @Version: v1.0
 */
@Service
@Slf4j
public class TestLockServiceImpl implements TestLockService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLocalLock() {
        String num = stringRedisTemplate.opsForValue().get("num");
        assert num != null;
        int i = Integer.parseInt(num);
        stringRedisTemplate.opsForValue().set("num", String.valueOf((++i)));
    }

    @Override
    public void testDistributedLock() {
        String lockKey = "lock";
        Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1");
        if (Boolean.TRUE.equals(aBoolean)) {
            String num = stringRedisTemplate.opsForValue().get("num");
            assert num != null;
            int i = Integer.parseInt(num);
            stringRedisTemplate.opsForValue().set("num", String.valueOf((++i)));
            stringRedisTemplate.delete(lockKey);
        } else {
            testDistributedLock();
        }
    }

    @Override
    public void testDistributedRedissonLock() {
//        v1LockNoTryCatchFinally();
//        v2LockTryCatchFinally();
//        v3LockNoArgs();
//        v4LockArgs();
//        v5TryLockNoArgs();
//        v6TryLockArgs();
    }

    private void v6TryLockArgs() {
        // 1. 获取锁对象
        RLock lock = redissonClient.getLock("abc");
        //锁在redis里面，自带续期功能，每隔10s对锁key进行自动续期到30s
        //底层技术：续期线程进行锁key续期
        // 2. 加锁
        // 自动两秒释放 没有续期功能
        // 100之内阻塞，之后不阻塞，不带续期
        boolean aBoolean = false;//有没有抢到锁，不会阻塞线程，
        try {
            aBoolean = lock.tryLock(100, 10, TimeUnit.SECONDS);
            if (aBoolean) {
                log.info("{}抢到了锁", Thread.currentThread().getName());
                try {
                    System.out.println("业务执行");
                    Thread.sleep(20000);
                    //如果有异常 还会继续续期，没有释放锁
                    //int i = 1/0;
                } finally {
                    // 3. 解锁
                    lock.unlock();
                }
            } else {
                //抢不到继续
                log.info("{}抢不到锁", Thread.currentThread().getName());
            }
            log.info("业务执行{}释放锁", Thread.currentThread().getName());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private void v5TryLockNoArgs() {
        // 1. 获取锁对象
        RLock lock = redissonClient.getLock("abc");
        //锁在redis里面，自带续期功能，每隔10s对锁key进行自动续期到30s
        //底层技术：续期线程进行锁key续期
        // 2. 加锁
        // 自动两秒释放 没有续期功能
        boolean aBoolean = lock.tryLock();//有没有抢到锁，不会阻塞线程，
        if (aBoolean) {
            log.info("{}抢到了锁", Thread.currentThread().getName());
            try {
                System.out.println("业务执行");
                Thread.sleep(20000);
                //如果有异常 还会继续续期，没有释放锁
                //int i = 1/0;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                // 3. 解锁
                lock.unlock();
            }
        } else {
            //抢不到继续
            log.info("{}抢不到锁", Thread.currentThread().getName());
        }
        log.info("业务执行{}释放锁", Thread.currentThread().getName());
    }

    private void v4LockArgs() {
        // 1. 获取锁对象
        RLock lock = redissonClient.getLock("abc");
        //锁在redis里面，自带续期功能，每隔10s对锁key进行自动续期到30s
        //底层技术：续期线程进行锁key续期
        // 2. 加锁
        // 自动两秒释放 没有续期功能
        lock.lock(10, TimeUnit.SECONDS);// 没抢到阻塞
        log.info("{}抢到了锁", Thread.currentThread().getName());
        try {
            System.out.println("业务执行");
            Thread.sleep(20000);
            //如果有异常 还会继续续期，没有释放锁
            //int i = 1/0;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 3. 解锁
            lock.unlock();
        }
        log.info("业务执行{}释放锁", Thread.currentThread().getName());
    }

    private void v3LockNoArgs() {
        // 1. 获取锁对象
        RLock lock = redissonClient.getLock("abc");
        //锁在redis里面，自带续期功能，每隔10s对锁key进行自动续期到30s
        //底层技术：续期线程进行锁key续期
        // 2. 加锁
        lock.lock();
        log.info("{}抢到了锁", Thread.currentThread().getName());
        try {
            System.out.println("业务执行");
            Thread.sleep(500);
            //如果有异常 还会继续续期，没有释放锁
            int i = 1 / 0;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 3. 解锁
            // 底层将续期任务取掉
            lock.unlock();//解锁要在trycatch的finally里面
        }
        log.info("业务执行{}释放锁", Thread.currentThread().getName());
    }

    private void v2LockTryCatchFinally() {
        RLock redissonLock = redissonClient.getLock("redissonLock");
        try {
            // 1. 获取分布式锁
            redissonLock.lock();
            log.info("{}抢到了锁", Thread.currentThread().getName());
            System.out.println("业务执行");
            Thread.sleep(10000);
            int i = 10 / 0;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            redissonLock.unlock();
        }
        log.info("{}释放了锁", Thread.currentThread().getName());
    }

    private void v1LockNoTryCatchFinally() {
        // 1. 获取分布式锁
        RLock redissonLock = redissonClient.getLock("redissonLock");
        redissonLock.lock();
        log.info("{}抢到了锁", Thread.currentThread().getName());
        System.out.println("业务执行");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        int i = 10 / 0;
        redissonLock.unlock();
        log.info("{}释放了锁", Thread.currentThread().getName());
    }
}

